/**
 * 验证工具模块
 * 提供各种数据验证方法和表单验证规则
 */

/** 表单验证规则接口 */
interface ValidatorRule {
  validator: (rule: any, value: any) => Promise<void>
  trigger: 'blur' | 'change' | string
}

/** 字段描述映射 */
const fieldsDesc: Record<string, string> = {}

/** 验证结果接口 */
interface ValidationResult {
  isPass: boolean
  message: string
}

/** 验证工具类 */
class Verify {
  
  /**
   * 检查对象是否为空
   * @param obj - 要检查的对象
   * @param ignore - 要忽略的字段数组
   * @returns Promise，解析为原对象或拒绝为错误消息
   */
  static emptyCheckObject<T extends Record<string, any>>(obj: T, ignore: string[] = []): Promise<T> {
    return new Promise((resolve, reject) => {
      const res: ValidationResult = {
        isPass: true,
        message: ''
      }

      for (const key in obj) {
        if (ignore.includes(key)) continue

        if (obj[key] == null || obj[key] === '') {
          const desc = fieldsDesc[key] ?? key
          res.message += res.isPass ? desc : '、' + desc
          res.isPass = false
        }
      }

      res.message += res.isPass === false ? '  不能为空' : ''
      
      if (!res.isPass) {
        reject(res.message)
      } else {
        resolve(obj)
      }
    })
  }

  /**
   * 检查标题是否包含特殊字符（中英文标点）
   * @param title - 要检查的标题
   * @returns 如果包含特殊字符返回true
   */
  static checkTitle(title: string): boolean {
    const chineseSymbols = "，。！？、；：（）"
    const englishSymbols = ",.!?;:+()/\\"

    return [...title].some(char => 
      chineseSymbols.includes(char) || englishSymbols.includes(char)
    )
  }

  /**
   * 验证手机号格式
   * @param phone - 手机号
   * @returns 是否是有效的手机号
   */
  static checkPhone(phone: string | number): boolean {
    return /^1[3|4|5|6|7|8|9]\d{9}$/.test(String(phone))
  }

  /**
   * 验证邮箱格式
   * @param email - 邮箱地址
   * @returns 是否是有效的邮箱
   */
  static checkEmail(email: string): boolean {
    return /^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/.test(email)
  }

  /**
   * 验证价格格式（不能为负，小数点不超过两位）
   * @param price - 价格
   * @returns 是否是有效的价格
   */
  static checkPrice(price: string | number): boolean {
    return /(^[1-9]\d*(\.\d{1,2})?$)|(^0(\.\d{1,2})?$)/.test(String(price))
  }

  /**
   * 验证是否为正整数
   * @param number - 要验证的数字
   * @returns 是否是正整数
   */
  static checkPositiveInteger(number: string | number): boolean {
    return /^[+]{0,1}(\d+)$/.test(String(number))
  }

  /**
   * 验证密码强度（包含数字、大小写字母、特殊字符，长度8-16位）
   * @param password - 密码
   * @returns 是否是有效的密码
   */
  static checkPassword(password: string): boolean {
    return /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*])[\da-zA-Z~!@#$%^&*]{8,16}$/.test(password)
  }

  /**
   * 验证身份证号
   * @param identityCode - 身份证号
   * @returns 是否是有效的身份证号
   */
  static checkIdentityCode(identityCode: string): boolean {
    return /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(identityCode) ||
           /^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$/.test(identityCode)
  }

  /**
   * 验证URL格式
   * @param url - URL地址
   * @returns 是否是有效的URL
   */
  static checkUrl(url: string): boolean {
    return /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/i.test(url)
  }

  /**
   * 检查是否包含中文字符
   * @param str - 要检查的字符串
   * @returns 是否包含中文字符
   */
  static checkChineseChar(str: string): boolean {
    return /[\u4e00-\u9fa5]/.test(str)
  }

  /**
   * 生成非空数组验证规则
   * @param message - 错误提示消息
   * @returns 验证规则数组
   */
  static ruleEmptyArray(message: string): ValidatorRule[] {
    return [{
      validator: (_rule: any, value: any[]) => {
        if (!value?.length) {
          return Promise.reject(new Error(message))
        }
        return Promise.resolve()
      },
      trigger: 'blur'
    }]
  }

  /**
   * 生成手机号验证规则
   * @returns 验证规则数组
   */
  static rulePhone(): ValidatorRule[] {
    return [{
      validator: (_rule: any, value: string) => {
        if (!value) {
          return Promise.reject(new Error('手机号不能为空'))
        }
        if (!Verify.checkPhone(value)) {
          return Promise.reject(new Error('手机号码格式不正确'))
        }
        return Promise.resolve()
      },
      trigger: 'blur'
    }]
  }

  /**
   * 生成价格验证规则
   * @returns 验证规则数组
   */
  static rulePrice(): ValidatorRule[] {
    return [{
      validator: (_rule: any, value: string | number) => {
        if (!value) {
          return Promise.reject(new Error('请填写价格'))
        }
        if (!Verify.checkPrice(value)) {
          return Promise.reject(new Error('价格不合法'))
        }
        return Promise.resolve()
      },
      trigger: 'blur'
    }]
  }

  /**
   * 生成正整数验证规则
   * @param message - 错误提示消息
   * @returns 验证规则数组
   */
  static rulePositiveInteger(message: string): ValidatorRule[] {
    return [{
      validator: (_rule: any, value: string | number) => {
        if (!value) {
          return Promise.reject(new Error(message))
        }
        if (!Verify.checkPositiveInteger(value)) {
          return Promise.reject(new Error(message))
        }
        return Promise.resolve()
      },
      trigger: 'blur'
    }]
  }

  /**
   * 生成URL验证规则
   * @returns 验证规则数组
   */
  static ruleUrl(): ValidatorRule[] {
    return [{
      validator: (_rule: any, value: string) => {
        if (!value) {
          return Promise.reject(new Error('请填写url'))
        }
        if (!Verify.checkUrl(value)) {
          return Promise.reject(new Error('url不合法'))
        }
        return Promise.resolve()
      },
      trigger: 'blur'
    }]
  }

  /**
   * 生成英文名称验证规则（不允许包含中文字符）
   * @returns 验证规则数组
   */
  static ruleEnglishName(): ValidatorRule[] {
    return [{
      validator: (_rule: any, value: string) => {
        if (!value) {
          return Promise.reject(new Error('请填写英文'))
        }
        if (Verify.checkChineseChar(value)) {
          return Promise.reject(new Error('存在中文字符'))
        }
        return Promise.resolve()
      },
      trigger: 'blur'
    }]
  }
}

export default Verify